Перейти к основному содержимому

6.11. Общее о проектировании и архитектуре

Разработчику Архитектору Аналитику

Общее о проектировании и архитектуре программного обеспечения

Обычно проектирование применяется к каким-то планам, схемам, моделям или расчётам, которые описывают будущий объект, включая характеристики, функции, инженерные решения. Создание, строительство и эксплуатация такого объекта выполняется по каким-то условиям, нормам и требованиям.

Дом, автомобиль, город — всё это системы, которые требуют проектирования составляющих компонентов. Аналогично, и программное обеспечение — это система, обладающая структурой, логикой внутренней организации и связями с внешним окружением. Вне зависимости от масштаба (одностраничный веб-интерфейс, мобильное приложение, распределённая корпоративная платформа), ПО существует в рамках ограничений, функциональных требований, ресурсов, времени, качества, сопровождаемости.

Поэтому необходима детализация идей, расчёты, выбор подходов и ресурсов, разработка спецификаций.


Почему так важно проектирование ПО?

Что такое проектирование?
Проектирование — процесс определения архитектуры, компонентов, интерфейсов и других характеристик системы или её части (ISO 24765, Международная организация по стандартизации).

Во многих практиках разработка начинается немедленно после получения первоначального описания задачи — без предварительного анализа, без моделирования, без согласования границ ответственности между компонентами. Причина, как правило, одна: дефицит времени. Однако такая экономия времени на начальной стадии неизбежно приводит к многократно возрастающим затратам на последующих этапах — при расширении функциональности, интеграции, исправлении дефектов, миграции на новую инфраструктуру или даже при обычном сопровождении.

Проектирование — это интеллектуальная деятельность, направленная на выработку структуры, которая:

  • делает систему понятной для команды разработчиков;
  • предотвращает распространение ошибок за пределы локальных зон ответственности;
  • позволяет разделять усилия: разные группы могут работать над разными частями одновременно, не нарушая целостности;
  • обеспечивает способность к адаптации — когда требования изменяются, изменения затрагивают минимально возможное число элементов;
  • снижает риски — архитектурные просчёты, выявленные на ранней стадии, стоят в разы дешевле, чем аналогичные, обнаруженные в продакшене.

Начинается всё с осмысления домена, с формулировки того, какие сущности, события и правила являются существенными для предметной области, какие взаимодействия являются постоянными, а какие — временными, какие зависимости допустимы, а какие — критичны. Без этого осмысления любая схема остаётся декорацией, а не инструментом принятия решений.


Архитектура как стратегический уровень проектирования

Архитектура программного обеспечения — это совокупность стратегических решений, определяющих основные структурные элементы системы, их взаимосвязи, а также принципы, по которым эти элементы взаимодействуют с внешним окружением. Она отвечает на вопросы: «Как будет организовано всё в целом?», «Какие части смогут меняться независимо?», «Какие технологии зададут пределы масштабируемости?», «Где будут находиться границы ответственности?».

Фактически, это живой процесс принятия решений, который продолжается на протяжении всего жизненного цикла проекта. Однако первоначальные архитектурные решения обладают наибольшей инерцией: изменить их позже — это перестройка. Поэтому ошибки на этом уровне особенно дорогостоящи, а порой даже непростительны.

Отсюда следует, что роль архитектора ПО — формулировать и отстаивать структурные ограничения, в рамках которых возможна дальнейшая разработка. Архитектор должен уметь:

  • видеть систему как единое целое, а не как набор отдельных модулей;
  • понимать технические возможности инструментов и их долгосрочные последствия — в плане сопровождаемости, безопасности, производительности, затрат на инфраструктуру;
  • идентифицировать слабые места в предлагаемых решениях до того, как они станут проблемами;
  • оценивать компромиссы между скоростью разработки, качеством, масштабируемостью и стоимостью владения.

Этот навык вырабатывается в ходе столкновения с ограничениями, с техническим долгом, с инцидентами, вызванными архитектурными просчётами. Опыт «горящих» проектов, где приходится принимать решения в условиях дефицита времени и ресурсов, зачастую даёт гораздо более глубокое понимание системных взаимосвязей, чем несколько лет стабильного развития. Именно поэтому профессиональный архитектор — это человек с большим стажем, прошедший через необходимость реструктуризации, рефакторинга, миграции, восстановления.


Системность

В практике часто под «системой» подразумевают отдельное приложение: веб-сайт, десктопную программу, мобильное приложение. Однако в реальных условиях, особенно в корпоративной и государственной среде, информационная система — это совокупность взаимосвязанных приложений, сервисов, хранилищ и внешних интеграций, которые вместе реализуют бизнес-процессы. Она не сводится к единому исполнимому файлу или даже к единому кодовому репозиторию.

Например, в системе электронного документооборота может быть:

  • модуль ввода заявок — реализован на Java и работает в контейнере;
  • модуль согласования — написан на C# и развёрнут как Windows-служба;
  • модуль хранения скан-копий — отдельное приложение на Python, интегрирующееся с файловым хранилищем;
  • модуль уведомлений — микросервис на Node.js, отправляющий сообщения в Telegram и почту;
  • внешние интеграции: ЕСИА, ГИС ЖКХ, реестр юридических лиц — каждый со своим протоколом и форматом.

Все эти элементы принадлежат одной логической системе, несмотря на различия в стеках, окружениях и жизненных циклах. Архитектура ПО в таком случае — это архитектура взаимодействия между компонентами. Именно здесь проявляется необходимость в чётких договорённостях: какие интерфейсы считаются стабильными, какие форматы данных обязательны, какие гарантии доставки требуются, как обрабатываются ошибки на стыке систем.

Это означает, что архитектурные решения должны учитывать внутреннюю структуру компонентов и их интерфейсы с внешним миром. Порт — это договорённость о контракте: какие данные ожидаются, в каком виде, с какими ограничениями, с какой семантикой. Нарушение этого контракта — нарушение целостности всей системы.


Уровни детализации

Часто термины архитектура и дизайн (технический дизайн, проектирование) используются как синонимы. Однако они относятся к разным уровням абстракции и разным целям.

Архитектура — это то, что трудно изменить позже без значительных затрат. Это выбор парадигмы (монолит, микросервисы), распределение ответственности между основными подсистемами, принятие решений о размещении данных (единая база, шардирование, полиглотное хранение), определение стратегии развертывания (одна среда, multi-tenant, multi-region), выбор протоколов синхронизации, политика управления зависимостями, границы контекстов (в терминах DDD), уровень изоляции компонентов.

Дизайн (техническое проектирование) — это то, как реализуется конкретный компонент внутри заданных архитектурных рамок. Это выбор паттернов проектирования (Factory, Strategy, Observer), организация классов и интерфейсов, структура базы данных (нормализация, денормализация), алгоритмы обработки, обработка исключений, логирование. Дизайн может меняться относительно часто, поскольку он оперирует в рамках уже утверждённой архитектурной модели.

Можно сказать, что архитектура определяет «каркас», а дизайн — «наполнение». Каркас должен быть прочным и гибким одновременно: он не должен ломаться под нагрузкой, но и не должен мешать строить внутри него новые помещения. Технический дизайн, в свою очередь, должен использовать возможности каркаса, а не пытаться его переопределить.


Уровни архитектурного рассмотрения

Понимание архитектуры требует системного взгляда. Для этого удобно выделять четыре уровня, каждый из которых отвечает на свой круг вопросов, формируя полную картину:


1. Функциональная архитектура

Этот уровень описывает, что система делает с точки зрения конечного пользователя или внешней системы. Здесь фиксируются бизнес-возможности: регистрация, авторизация, оплата, поиск, генерация отчётов. Акцент делается на сценариях использования: «пользователь оформляет заказ», «оператор подтверждает оплату», «администратор настраивает тарифы».

Функциональная архитектура — это мост между бизнес-аналитикой и технической реализацией. Она помогает избежать ситуации, когда разработчики идеально реализуют техническое задание, но полученный результат не решает реальную бизнес-задачу. На этом уровне строятся use-case диаграммы, пользовательские истории, потоки действий — всё, что позволяет убедиться: мы строим ту систему, которая действительно нужна.


2. Архитектура предметной области (домена)

Если функциональная архитектура говорит что, то архитектура домена говорит почему и как с точки зрения бизнес-логики. Здесь выделяются ключевые сущности: Пользователь, Заказ, Счёт, Транзакция; определяются бизнес-правила: «нельзя отменить платёж после подтверждения банком», «скидка применяется только к товарам категории А», «статус заявки меняется только при наличии подписи уполномоченного лица»; фиксируются неизменяемые события: «Заказ создан», «Платёж проведён», «Документ согласован».

Этот уровень не зависит от технологий. Он может быть описан в терминах UML-диаграмм классов, Event Storming-сессий, онтологий или просто текстом — главное, чтобы отражалась семантика предметной области. Архитектура домена — это основа для DDD (Domain-Driven Design), и она позволяет выстраивать границы агрегатов, выделять ограниченные контексты и тем самым минимизировать межкомпонентные зависимости.


3. Прикладная архитектура

Здесь начинается переход от абстракций к реализации. Прикладная архитектура отвечает на вопрос: как реализованы функции и правила? Это уровень компонентов, модулей, сервисов, API, протоколов взаимодействия. Здесь определяется, как компоненты передают друг другу данные: через REST, gRPC, сообщения в очереди, shared memory; как организованы границы: по функциональным зонам («платежи», «доставка»), по типам операций (CRUD-сервисы, вычислительные ядра), по уровням доступа (публичный API, внутренние сервисы, админка).

Прикладная архитектура — это уровень, где материализуются архитектурные стили (слоистая, гексагональная, чистая архитектура). Именно здесь проявляется, насколько удачно были выделены границы ответственности: если изменение в одном модуле требует правок в десяти других — границы проведены некорректно.


4. Технологическая архитектура

Этот уровень отвечает за инфраструктурную реализацию: где и как размещаются компоненты, какие ресурсы для них выделяются, как обеспечивается отказоустойчивость, масштабируемость, безопасность. Сюда входят: выбор облачной платформы (AWS, Azure, Yandex Cloud) или on-premise-развёртывания, типы баз данных (реляционные, документные, временные ряды), использование контейнеризации (Docker, Kubernetes), настройка сетей (VPC, зоны доступности), системы мониторинга и логирования (Prometheus, ELK), стратегии резервного копирования.

Технологическая архитектура — это логика размещения и взаимодействия ресурсов. Например, решение разнести компоненты по разным availability zones — это архитектурное решение, направленное на достижение отказоустойчивости. Использование read-replicas для снятия нагрузки с основной базы — тоже архитектурное решение. Оно должно приниматься осознанно, а не как побочный эффект от «просто поставили Kubernetes».

Изменения на одном уровне неизбежно влияют на другие. Например, решение перейти на микросервисы (прикладная архитектура) потребует пересмотра стратегии деплоя (технологическая), может повлиять на выделение границ домена (архитектура домена) и даже изменить пользовательский сценарий (функциональная — если появляются асинхронные уведомления о статусе).


Проектирование как процесс

Проектирование — это непрерывный цикл выявления требований, формирования гипотез, проверки их на практике и корректировки структуры. Оно включает техническую, коммуникационную и документационную составляющие.


Почему схемы важны

Схема — это упрощённое графическое или текстовое представление структуры, устройства, процесса или взаимосвязей между элементами системы. Она фокусируется на существенных характеристиках объекта, опуская второстепенные детали, чтобы сделать информацию более понятной, обозримой и пригодной для анализа или передачи.

Схемы — это инструмент мышления, позволяющий выйти за пределы линейного описания и увидеть систему как целое. Текст хорошо передаёт последовательности и условия; схема — структуру, связи, иерархию, потоки.

Они используются на всех уровнях проектирования и документирования:

  • Архитектурные схемы показывают компоненты системы (серверы, базы данных, микросервисы), их роли и способы взаимодействия. Пример — диаграмма «компоненты и соединения» (component-and-connector diagram).

  • Схемы данных отображают структуру хранилищ: таблицы, поля, связи, типы данных. Такие схемы могут быть логическими (независимо от СУБД) или физическими (с учётом особенностей конкретной базы данных).

  • Схемы пользовательских интерфейсов (wireframes) демонстрируют расположение элементов на экране, навигацию и потоки взаимодействия пользователя с системой.

  • Схемы процессов (например, BPMN-диаграммы или flowcharts) описывают последовательность шагов в бизнес-процессе или алгоритме.

  • Схемы сетевой инфраструктуры иллюстрируют топологию сети, маршрутизацию трафика, зоны безопасности и точки подключения.

Три ключевые функции схем:

  1. Декомпозиция сложности. Система в целом может быть непостижима. Схема позволяет выделить части (компоненты, зоны, контексты), ограничить внимание и рассмотреть каждую отдельно, не теряя связи с общим контекстом.

  2. Выявление скрытых зависимостей. В текстовом описании легко упустить косвенную связь: «модуль A вызывает модуль B, который сохраняет данные, которые потом читает модуль C». На диаграмме такая цепочка становится видимой. Это позволяет обнаружить циклические зависимости, узкие места, точки единого отказа до реализации.

  3. Согласование понимания в команде. Когда несколько человек смотрят на одну и ту же схему, они обсуждают конкретные блоки и стрелки. Это снижает вероятность недопонимания: «под сервисом X я имел в виду именно этот блок, а не тот». Схема — это общий язык, особенно важный при участии нетехнических специалистов (аналитики, заказчики).

Схема должна быть достаточно точной, но не перегруженной. Диаграмма уровня 0 (системный контекст) показывает только внешние системы и основные потоки. Диаграмма уровня 1 (прикладная архитектура) — компоненты и их интерфейсы. Диаграмма уровня 2 — внутреннее устройство одного компонента. Каждый уровень служит своей цели и своей аудитории. Перемешивание уровней (например, на общей схеме рисовать сервисы и классы внутри них) делает схему бесполезной.

Рекомендуемые типы схем для проектирования:

  • C4 Model (Context, Containers, Components, Code) — иерархическая система диаграмм, позволяющая описывать систему на четырёх уровнях детализации. Особенно эффективна для документирования и передачи знаний.
  • Схемы потоков данных (DFD) — фокус на том, как данные перемещаются между процессами, хранилищами и внешними сущностями. Полезны на ранних стадиях, когда ещё не решено, какие будут компоненты.
  • UML-диаграммы (Component, Deployment, Sequence) — при условии их умеренного использования. Диаграммы компонентов и развёртывания помогают прояснить физическую и логическую структуру; sequence-диаграммы — уточнить взаимодействие в критических сценариях.
  • Event Storming-карты — совместное моделирование домена через выделение событий, команд, агрегатов. Это результат workshop’а, фиксирующий коллективное понимание.

Схемы теряют ценность, если они:

  • создаются «для галочки» и не обсуждаются;
  • не обновляются при изменении архитектуры;
  • слишком абстрактны («Бизнес-логика» → «Хранилище») или, наоборот, переполнены деталями.

Идеальная схема — та, которую можно распечатать, повесить на стену и использовать как опору для разговора.


Планирование

Планирование — это процесс определения целей, задач, ресурсов, сроков и последовательности действий, необходимых для достижения желаемого результата. Это систематическая деятельность, направленная на организацию будущих шагов с учётом имеющихся ограничений и возможностей.

В контексте разработки программного обеспечения планирование охватывает несколько уровней:

  • Стратегическое планирование — определение долгосрочного видения продукта, его целевой аудитории, основных ценностей и направлений развития.
  • Архитектурное планирование — проектирование структуры системы, выбор технологического стека, определение модульности, масштабируемости и принципов взаимодействия компонентов.
  • Проектное планирование — разбиение работы на этапы, формирование дорожной карты (roadmap), оценка трудозатрат, распределение ролей в команде.
  • Операционное планирование — составление ежедневных или еженедельных задач, планирование спринтов в гибких методологиях, контроль выполнения и адаптация к изменениям.

Планирование проектирования начинается с уточнения ограничений и критериев качества. Нефункциональные требования (NFR) — это не «желательно быстро работать», а:

  • «Система должна обрабатывать до 5000 запросов в секунду с 95-м перцентилем задержки ≤ 200 мс»;
  • «Данные должны быть доступны с гарантией 99.99% uptime в течение года»;
  • «Изменение налоговой ставки должно вступать в силу в течение 5 минут без перезапуска»;
  • «Нарушение безопасности одного компонента не должно давать доступ к данным пользователей в других».

Эти требования напрямую влияют на архитектурные решения. Например:

  • требование низкой задержки может исключить синхронные вызовы между микросервисами;
  • требование мгновенного обновления правил может сделать невозможным хардкодинг логики в бинарниках;
  • требование изоляции — повлечь необходимость в multi-tenancy на уровне БД или даже отдельных инстансах.

Планирование включает:

  • выявление ключевых сценариев (пиковая нагрузка, восстановление после сбоя, развёртывание новой функции);
  • оценку рисков (что сломается первым? где будут узкие места?);
  • выбор критериев для сравнения вариантов (стоимость, время вывода на рынок, гибкость, обучаемость);
  • определение границ экспериментов: что можно проверить быстро (например, через spike-реализацию), что требует прототипа, а что — фундаментального решения.

Планирование не даёт «правильного» ответа, а помогает обосновать выбор и зафиксировать, почему принято то или иное решение — особенно если позже возникнет необходимость его пересмотреть.


Архитектурные решения

Каждое существенное архитектурное решение должно быть зафиксировано в виде документа, доступного всей команде. Для этого используются ADR (Architecture Decision Records) — лёгкие, структурированные записи вида:

  • Контекст: какая проблема или ограничение требует решения?
  • Варианты: какие альтернативы рассматривались?
  • Решение: что выбрано и почему?
  • Последствия: какие преимущества и недостатки несёт это решение? какие компромиссы сделаны?

ADR — это документ, фиксирующий важное техническое или архитектурное решение, принятое в ходе разработки программного обеспечения. Обычно включает в себя краткое название решения, статус, описание ситуации/проблемы/требований, которые привели к необходимости принятия решения и собственно само решение, конкретный выбор, который был сделан.

ADR обычно хранятся в репозитории проекта, рядом с исходным кодом, часто в формате Markdown. Это позволяет версионировать их вместе с кодом и отслеживать эволюцию архитектуры во времени.

Пример:

Контекст: Необходимо реализовать интеграцию с 5 платёжными системами, каждая из которых меняет API раз в 6–12 месяцев.
Варианты:

  1. Жёстко закодировать логику в одном модуле.
  2. Выделить общий интерфейс и реализовать адаптеры для каждой системы.
  3. Использовать внешний оркестратор (например, Apache Camel).
    Решение: Вариант 2 — гексагональный подход с портом IPaymentGateway.
    Последствия:
  • Новые платёжные системы подключаются без изменения ядра.
  • Тестирование проще (можно мокать адаптеры).
    – Требуется больше начальных усилий на выделение интерфейса.

ADR — это история рассуждений, позволяющая новым членам команды понять, почему система устроена именно так, и избежать повторного обсуждения уже решённых вопросов. Со временем ADR образуют карту архитектурной эволюции проекта.

Применение ADR особенно полезно в долгосрочных проектах, где архитектура развивается постепенно, и важно понимать, почему были выбраны те или иные компоненты. Это снижает риск повторного обсуждения уже решённых вопросов и помогает избежать ошибок, связанных с неполным пониманием прошлых решений.


Командная работа

Даже в небольшой команде важно вовлекать разработчиков в проектирование для выявления скрытых проблем. Тот, кто будет писать код, часто видит практические сложности раньше, чем теоретик.

Эффективные практики:

  • Architecture Kata — совместное решение архитектурной задачи за ограниченное время. Задаётся контекст («нужно построить систему бронирования для 10 млн пользователей»), и команда за 60–90 минут вырабатывает вариант архитектуры, рисует схему, оценивает риски. Это тренирует системное мышление.
  • Lightweight Architecture Decision Sessions — короткие встречи (30–45 мин) для принятия одного конкретного решения с участием ключевых участников (разработчик, техлид, аналитик, инфраструктурщик). Фокус — на аргументах, а не на голосовании.
  • Architecture Review on Pull Requests — код-ревью и проверка, не нарушает ли изменение архитектурные границы, не вносит ли новые циклические зависимости, не ломает ли контракты.

Проектирование — это инвестиция в предсказуемость. Команда, которая тратит 10% времени на осмысление структуры, экономит 50% времени на исправлении последствий спонтанных решений.